#include "stdafx.h"
#include "View.h"

WMReaderView::WMReaderView()
{
    CreateClientWindow();
}

void WMReaderView::CreateClientWindow()
{
    CreateMainWindow();
    CreateMenuBar();
    CreateTabControl();
    CreateFileSystemTab();
    CreateRegistryTab();
    CreateInfoTab();
    CreateStatusBar();
    ShowClientWindow();
}

void WMReaderView::CreateMainWindow()
{
    m_MainWindow = new QMainWindow(0, Qt::WindowTitleHint |
                                      Qt::WindowSystemMenuHint |
                                      Qt::WindowMinMaxButtonsHint);
    m_MainWindow->setWindowTitle(tr("WM Reader"));

    size_t deskWidth = QApplication::desktop()->width();
    size_t deskHeight = QApplication::desktop()->height();

    m_MainWindow->setGeometry(deskWidth / 2 - client_set::clientWidth / 2,
                              deskHeight /2 - client_set::clientHeight / 2,
                              client_set::clientWidth,
                              client_set::clientHeight);
    QApplication::setWindowIcon(QIcon(client_ico::app));
}

void WMReaderView::CreateMenuBar()
{
    m_MenuBar = new QMenuBar();
    m_FileMenu = new QMenu(tr("File"), m_MenuBar);
    m_HelpMenu = new QMenu(tr("Help"), m_MenuBar);  

    m_MenuBar->addMenu(m_FileMenu);
    m_MenuBar->addMenu(m_HelpMenu);

    m_ConnectAction = new QAction(tr("Connect"), m_FileMenu);
    m_ConnectAction->setIcon(QIcon(client_ico::connect));
    m_ConnectAction->setShortcut(Qt::Key_F5);
    connect(m_ConnectAction, SIGNAL(triggered()), this, SLOT(ConnectToDevice()));

    m_DisconnectAction = new QAction(tr("Disconnect"), m_FileMenu);
    m_DisconnectAction->setIcon(QIcon(client_ico::disconnect));
    m_DisconnectAction->setShortcut(QKeySequence(Qt::SHIFT+ Qt::Key_F5));
    m_DisconnectAction->setDisabled(true);
    connect(m_DisconnectAction, SIGNAL(triggered()), this, SLOT(DisconnectFromDevice()));    

    m_FileMenu->addSeparator();

    m_ExitAction = new QAction(tr("Exit"), m_FileMenu);
    m_ExitAction->setIcon(QIcon(client_ico::quit));
    m_ExitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
    connect(m_ExitAction, SIGNAL(triggered()), m_MainWindow, SLOT(close()));

    m_AboutAction = new QAction(tr("About"), m_HelpMenu);
    m_AboutAction->setIcon(QIcon(client_ico::about));
    m_AboutAction->setShortcut(Qt::Key_F1);      
    connect(m_AboutAction, SIGNAL(triggered()), this, SLOT(ShowAboutWindow()));          
    
    m_FileMenu->addAction(m_ConnectAction);
    m_FileMenu->addAction(m_DisconnectAction);
    m_FileMenu->addAction(m_ExitAction);
    m_HelpMenu->addAction(m_AboutAction);    

    m_MainWindow->setMenuBar(m_MenuBar);
}

void WMReaderView::CreateTabControl()
{
    m_TabControl = new QTabWidget();
    m_MainWindow->setCentralWidget(m_TabControl);
}

void WMReaderView::CreateFileSystemTab()
{
    m_FileSystemTree = new QTreeWidget();
    m_FileSystemTree->setColumnCount(client_set::fileSystemColumnsNum);
    m_FileSystemTree->sortByColumn(0, Qt::AscendingOrder);   
    m_FileSystemTree->setSortingEnabled(true);
    
    m_FileSystemTree->setStyleSheet(client_set::treeWidgetStyle);

    QStringList fileSystemTabHeaders;
    fileSystemTabHeaders << tr("Name")
                         << tr("Size")
                         << tr("Type")
                         << tr("Last modified");
    m_FileSystemTree->setHeaderLabels(fileSystemTabHeaders);

    for(size_t i = 0; i < client_set::fileSystemColumnsNum; ++i)
        m_FileSystemTree->setColumnWidth(i, client_set::fileSystemColumnsWidth);

    m_FileSystemTop = new QTreeWidgetItem();
    m_FileSystemTop->setText(0, tr("/"));
    m_FileSystemTop->setIcon(0, QIcon(client_ico::drive));
    m_FileSystemTop->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
    m_FileSystemTree->addTopLevelItem(m_FileSystemTop);

    connect(m_FileSystemTree, SIGNAL(itemExpanded(QTreeWidgetItem*)), 
            this, SLOT(RetrieveFileSystem(QTreeWidgetItem*)));
    connect(m_FileSystemTree, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
            this, SLOT(ClearChildItems(QTreeWidgetItem*)));   

    m_TabControl->addTab(m_FileSystemTree, tr("File System"));
}

void WMReaderView::CreateRegistryTab()
{
    m_RegistryTree = new QTreeWidget();
    m_RegistryTree->sortByColumn(0, Qt::AscendingOrder);
    m_RegistryTree->setSortingEnabled(true);
    m_RegistryTree->setHeaderLabel(tr("Keys"));

    m_RegistryValuesList = new QTreeWidget();
    m_RegistryValuesList->sortByColumn(0, Qt::AscendingOrder);
    m_RegistryValuesList->setSortingEnabled(true);

    m_RegistryValuesList->setStyleSheet(client_set::treeWidgetStyle);

    m_RegistryValuesList->setColumnCount(client_set::registryValuesColumnNum);

    QStringList registryValueLabels;
    registryValueLabels << tr("Name")
                        << tr("Type")
                        << tr("Value");
    m_RegistryValuesList->setHeaderLabels(registryValueLabels);

    for(size_t i = 0; i <  client_set::registryValuesColumnNum; ++i)
        m_RegistryValuesList->setColumnWidth(i, client_set::registryValuesColumnsWidth);

    QWidget *registryHolder = new QWidget();

    QSplitter *registrySplitter = new QSplitter();
    registrySplitter->setHandleWidth(client_set::registrySplitterWidth);
    registrySplitter->addWidget(m_RegistryTree);
    registrySplitter->addWidget(m_RegistryValuesList);
    registrySplitter->setSizes(QList<int>() << 100 << 300);
    registrySplitter->setOrientation(Qt::Horizontal);

    QHBoxLayout *registryLayout = new QHBoxLayout();
    registryLayout->addWidget(registrySplitter);
    registryHolder->setLayout(registryLayout);

    m_RegistryTop = new QTreeWidgetItem();
    m_RegistryTop->setText(0, tr("Mobile device"));
    m_RegistryTop->setIcon(0, QIcon(client_ico::phone));
    m_RegistryTop->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
    m_RegistryTree->addTopLevelItem(m_RegistryTop);

    connect(m_RegistryTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
            this, SLOT(RetrieveRegistryKeysList(QTreeWidgetItem*)));
    connect(m_RegistryTree, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
            this, SLOT(ClearChildItems(QTreeWidgetItem*)));
    connect(m_RegistryTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
            this, SLOT(RetrieveRegistryKeyValues(QTreeWidgetItem*, int)));

    m_TabControl->addTab(registryHolder, tr("Registry"));   
}

void WMReaderView::CreateInfoTab()
{
    m_InfoTree = new QTreeWidget();
    m_InfoTree->setColumnCount(client_set::infoColumnNum);

    QStringList infoLabels;
    infoLabels << tr("Properties")
               << tr("Values");
    m_InfoTree->setHeaderLabels(infoLabels); 

    for(size_t i = 0; i <  client_set::infoColumnNum; ++i)
        m_InfoTree->setColumnWidth(i, client_set::infoColumnsWidth);

    m_InfoTree->setStyleSheet(client_set::treeWidgetStyle);

    m_InfoTop = new QTreeWidgetItem();
    m_InfoTop->setText(0, tr("Information"));
    m_InfoTop->setIcon(0, QIcon(client_ico::info));
    m_InfoTop->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
    m_InfoTree->addTopLevelItem(m_InfoTop);

    connect(m_InfoTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
            this, SLOT(RetrieveDeviceInfo(QTreeWidgetItem*)));
    connect(m_InfoTree, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
            this, SLOT(ClearDeviceInfoItems(QTreeWidgetItem*)));

    m_TabControl->addTab(m_InfoTree, tr("Device information"));
}

void WMReaderView::CreateStatusBar() 
{
    m_ConnectStatus = new QLabel();
    m_ConnectStatus->setText(tr("<b>Disconnected</b>"));

    m_ConnectIcon = new QLabel();
    m_ConnectIcon->setPixmap(QPixmap(client_ico::disconnected));
    
    m_StatusBar = new QStatusBar();
    m_StatusBar->addWidget(m_ConnectIcon, 0); 
    m_StatusBar->addWidget(m_ConnectStatus, 0);
    
    m_MainWindow->setStatusBar(m_StatusBar);
}

void WMReaderView::ShowClientWindow()
{
    m_MainWindow->show();
}

void WMReaderView::SetConnected(bool connected)
{
    if(connected == true) {
        m_ConnectStatus->setText(tr("<b>Connected</b>"));
        m_ConnectIcon->setPixmap(QPixmap(client_ico::connected));
    } else {
        m_ConnectStatus->setText(tr("<b>Disconnected</b>"));
        m_ConnectIcon->setPixmap(QPixmap(client_ico::disconnected));
    }
}

void WMReaderView::ShowAboutWindow()
{
    QMessageBox::about(m_MainWindow,
                       tr("About WM Reader"),
                       tr("<b>WM Reader</b><br/>"
                       "Version: 1.0<br/>"
                       "Authors: Aleksei Dyakov, Dmitriy Simbiriatin<br/>"
                       "Copyright &copy; 2011 Dyakov Aleksei, Simbiriatin Dmitiy<br/>"
                       "License: GPL version 2"));
}

void WMReaderView::ShowErrorMessage(const QString &message)
{
    QMessageBox::critical(m_MainWindow, tr("WM Reader - Error"), message);
}

void WMReaderView::ClearChildItems(QTreeWidgetItem *topItem)
{
    if(topItem->childCount() > 0)
        qDeleteAll(topItem->takeChildren());    
}

void WMReaderView::ClearDeviceInfoItems(QTreeWidgetItem *topItem)
{
    if(topItem->parent() == NULL)
        ClearChildItems(topItem);
}

void WMReaderView::ConnectToDevice()
{
    emit RequestConnectToDevice();
}

void WMReaderView::DeviceConnected()
{
    m_ConnectAction->setDisabled(true);
    m_DisconnectAction->setEnabled(true);
    SetConnected(true);
}

void WMReaderView::DisconnectFromDevice()
{
    emit RequestDisconnectFromDevice();
}

void WMReaderView::DeviceDisconnected()
{
    m_ConnectAction->setEnabled(true);
    m_DisconnectAction->setDisabled(true);
    SetConnected(false);

    m_FileSystemTree->collapseItem(m_FileSystemTop);
    m_RegistryTree->collapseItem(m_RegistryTop);
    m_InfoTree->collapseItem(m_InfoTop);
    m_RegistryValuesList->clear();
}

void WMReaderView::RetrieveFileSystem(QTreeWidgetItem *topItem)
{
    emit RequestFileSystem(topItem);
}

void WMReaderView::RetrieveRegistryKeysList(QTreeWidgetItem *topItem)
{
    if (topItem->parent() == NULL) {
        ShowPredefinedRegKeys();
    } else {
        emit RequestRegistryKeysList(topItem);
    }
}

void WMReaderView::RetrieveRegistryKeyValues(QTreeWidgetItem* topItem, int)
{
    if(topItem->parent() != NULL)
        emit RequestRegistryKeyValues(topItem);
}

void WMReaderView::RetrieveDeviceInfo(QTreeWidgetItem *topItem)
{
    if(topItem->parent() == NULL)
        emit RequestDeviceInfo();
}

void WMReaderView::ShowPredefinedRegKeys()
{ 
    QStringList preDefKeys;
    preDefKeys << "HKEY_CLASSES_ROOT" 
               << "HKEY_CURRENT_USER"
               << "HKEY_LOCAL_MACHINE"
               << "HKEY_USERS";

    for(size_t i = 0; i < registry_set::preDefKeysNumber; ++i) {
        QTreeWidgetItem *key = new QTreeWidgetItem();
        key->setText(0, preDefKeys[i]);
        key->setIcon(0, QIcon(client_ico::folder));
        key->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
        m_RegistryTop->addChild(key);
    }
}

void WMReaderView::FileSystemRetrieved(QTreeWidgetItem *topItem, std::vector <CE_FIND_DATA> *fileSystemItems)
{
    if(fileSystemItems->empty()) {
        topItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); 
    } else {
        std::vector <CE_FIND_DATA>::iterator it;

        for(it = fileSystemItems->begin(); it < fileSystemItems->end(); ++it) {         

            QTreeWidgetItem *childItem = new QTreeWidgetItem(topItem);
            childItem->setText(0, QString::fromWCharArray(it->cFileName));
            
            if(it->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                childItem->setText(2, tr("Folder"));
                childItem->setIcon(0, QIcon(client_ico::folder));
                childItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
            } else {
                childItem->setText(2, tr("File"));
                childItem->setIcon(0, QIcon(client_ico::file));
                
                size_t size = (it->nFileSizeHigh * MAXDWORD) + it->nFileSizeLow;
                childItem->setData(1, Qt::DisplayRole, size);
            }
    
            QString modifTime;
            WMReaderUtils::FileTimeToQString(it->ftLastWriteTime, modifTime);
            childItem->setText(3, modifTime);
        }   
    }
}

void WMReaderView::RegistryKeysListRetrieved(QTreeWidgetItem *topItem, std::vector <registry_set::REGKEY> *registryKeys)
{
    if(registryKeys->empty()) {
        topItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
    } else {  
        std::vector <registry_set::REGKEY>::iterator it;

        for(it = registryKeys->begin(); it < registryKeys->end(); ++it) {
            QTreeWidgetItem *childItem = new QTreeWidgetItem(topItem);
            childItem->setText(0, QString::fromWCharArray(it->regKey));
            childItem->setIcon(0, QIcon(client_ico::folder));
            childItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);   
        }
    } 
}

void WMReaderView::RegistryKeyValuesRetrieved(std::vector <registry_set::REGKEYVALUE> *keyValues)
{
    m_RegistryValuesList->clear();

    if(!keyValues->empty()) {        
        std::vector <registry_set::REGKEYVALUE>::iterator it;

        for(it = keyValues->begin(); it < keyValues->end(); ++it) {          

            QTreeWidgetItem *childItem = new QTreeWidgetItem(m_RegistryValuesList); 
            childItem->setText(0, QString::fromWCharArray(it->valueName));

            std::wstring value;
            std::wstringstream stream;

            switch(it->valueType) {
                case REG_DWORD:
                    stream << *(reinterpret_cast<LPDWORD>(it->valueBuffer));
                    value = stream.str();
                    childItem->setText(1, "REG_DWORD");
                    childItem->setText(2, QString::fromStdWString(value));
                    childItem->setIcon(0, QIcon(client_ico::reg_dword));
                    stream.clear(); stream.str(L""); value = L"";
                    break;
                case REG_MULTI_SZ:
                case REG_SZ:
                    value = reinterpret_cast<const wchar_t*>(it->valueBuffer);
                    childItem->setText(1, "REG_SZ");
                    childItem->setText(2, QString::fromStdWString(value));
                    childItem->setIcon(0, QIcon(client_ico::reg_string));
                    value = L"";
                    break;
                case REG_BINARY:
                    stream.setf(std::ios_base::hex, std::ios::basefield);
                    stream.setf(std::ios_base::uppercase);

                    for (size_t i = 0; i <= static_cast<size_t>(it->bufferSize); ++i)
                          stream << *(it->valueBuffer + i);

                    value = stream.str();
                    childItem->setText(1, "REG_BINARY");
                    childItem->setText(2, QString::fromStdWString(value));
                    childItem->setIcon(0, QIcon(client_ico::reg_binary));

                    stream.unsetf(std::ios_base::hex);
                    stream.unsetf(std::ios::basefield);
                    stream.unsetf(std::ios_base::uppercase);
                    stream.clear(); stream.str(L""); value = L"";
                    break;
            }
        }
    }
}

void WMReaderView::DeviceInfoRetrieved(std::vector<device_info::DEVICEINFO> *deviceInfo)
{
    std::vector <device_info::DEVICEINFO>::iterator it = deviceInfo->begin();

    QFont boldFont("", -1, QFont::Bold);  

    QTreeWidgetItem *osVersion = new QTreeWidgetItem(m_InfoTop);
    osVersion->setFont(0, boldFont);
    osVersion->setText(0, tr("OS version:"));
    osVersion->setIcon(0, QIcon(client_ico::desktop));
    osVersion->setText(1, QString("Windows CE %1.%2 build %3").arg(it->osMajorVersion)
                                                              .arg(it->osMinVersion)
                                                              .arg(it->osBuildNumber)); 

    QTreeWidgetItem *processor = new QTreeWidgetItem(m_InfoTop);
    processor->setFont(0, boldFont);
    processor->setText(0, tr("Processor:"));
    processor->setIcon(0, QIcon(client_ico::processor));
    
    QString procType;
    WMReaderUtils::ProcTypeToString(it->procType, procType);
    processor->setText(1, procType);

    QTreeWidgetItem *memory = new QTreeWidgetItem(m_InfoTop);
    memory->setFont(0, boldFont);
    memory->setText(0, "Memory:");
    memory->setIcon(0, QIcon(client_ico::memory));
    memory->setText(1, QString("%1%").arg(it->memoryLoad));
    memory->setExpanded(true);

    QStringList memoryProp, memoryVal;
    memoryProp << tr("Total physical memory:")
               << tr("Available physical memory:")
               << tr("Total virtual memory:")
               << tr("Available virtual memory:");

    memoryVal << QString(tr("%1 Mb")).arg(WMReaderUtils::BytesToMbs(it->totalPhysMem))
              << QString(tr("%1 Mb")).arg(WMReaderUtils::BytesToMbs(it->availPhysMem))
              << QString(tr("%1 Mb")).arg(WMReaderUtils::BytesToMbs(it->totalVirtMem))
              << QString(tr("%1 Mb")).arg(WMReaderUtils::BytesToMbs(it->availVirtMem));

    for(size_t i = 0; i < client_set::memoryPropNum; ++i) {
        QTreeWidgetItem *memoryItem = new QTreeWidgetItem(memory);
        memoryItem->setIcon(0, QIcon(client_ico::memory));
        memoryItem->setText(0, memoryProp[i]);
        memoryItem->setText(1, memoryVal[i]);
    }

    QTreeWidgetItem *display = new QTreeWidgetItem(m_InfoTop);
    display->setFont(0, boldFont);
    display->setText(0, tr("Display:"));
    display->setIcon(0, QIcon(client_ico::display));
    display->setExpanded(true);

    QStringList displayProp, displayVal;
    displayProp << tr("Width:")
                << tr("Height:")
                << tr("Bits per pixel:");

    displayVal << QString(tr("%1 px")).arg(it->displayWidth)
               << QString(tr("%1 px")).arg(it->displayHeight)
               << QString(tr("%1 bit")).arg(it->displayBits);
    
    for(size_t i = 0; i < client_set::displayPropNum; ++i) {
        QTreeWidgetItem *displayItem = new QTreeWidgetItem(display);
        displayItem->setIcon(0, QIcon(client_ico::display));
        displayItem->setText(0, displayProp[i]);
        displayItem->setText(1, displayVal[i]);
    }

    QTreeWidgetItem *battery = new QTreeWidgetItem(m_InfoTop);
    battery->setFont(0, boldFont);
    battery->setText(0, tr("Battery:"));
    battery->setIcon(0, QIcon(client_ico::battery));
    battery->setText(1, QString("%1%").arg(it->batStatus));
}